package com.tsd.jxc.stock.service.impl;

import com.tsd.base.service.BaseCodeRuleService;
import com.tsd.common.vo.BatchDeleteLogicVo;
import com.tsd.core.constants.Constants;
import com.tsd.core.service.GetDuplicatedObj;
import com.tsd.core.thread.ThreadPoolTaskUtil;
import com.tsd.core.utils.DateUtil;
import com.tsd.core.utils.DoubleUtil;
import com.tsd.core.utils.HlpUtils;
import com.tsd.core.utils.ListUtil;
import com.tsd.core.vo.ErrorCode;
import com.tsd.core.vo.HlpException;
import com.tsd.core.vo.HttpResult;
import com.tsd.core.vo.PageBean;
import com.tsd.jxc.buy.dao.JxcBuyOrderDetailMapper;
import com.tsd.jxc.buy.dao.JxcBuyOrderMapper;
import com.tsd.jxc.config.JxcCodeRuleConstants;
import com.tsd.jxc.sale.dao.JxcSaleReturnBillDetailMapper;
import com.tsd.jxc.sale.dao.JxcSaleReturnBillMapper;
import com.tsd.jxc.stock.StockConstants;
import com.tsd.jxc.stock.dao.JxcStockGoodsMapper;
import com.tsd.jxc.stock.dao.JxcStockInbillItemMapper;
import com.tsd.jxc.stock.dao.JxcStockInbillMapper;
import com.tsd.jxc.stock.entity.JxcStockInbill;
import com.tsd.jxc.stock.entity.JxcStockInbillExt;
import com.tsd.jxc.stock.entity.JxcStockInbillItemExt;
import com.tsd.jxc.stock.job.JxcStockJob;
import com.tsd.jxc.stock.service.JxcStockInbillItemService;
import com.tsd.jxc.stock.service.JxcStockInbillService;
import com.tsd.jxc.utils.JxcUtils;
import com.tsd.service.BaseServiceImpl;
import com.tsd.system.entity.SysUser;
import com.tsd.system.entity.SysUserExt;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 描述：JxcStockInbill 服务实现层
 *
 * @author Hillpool
 * @date 2022/07/29 15:06:33
 */
@Service
public class JxcStockInbillServiceImpl extends BaseServiceImpl implements JxcStockInbillService, GetDuplicatedObj {

    @Resource
    private JxcStockInbillMapper jxcStockInbillMapper;
    @Resource
    private JxcStockInbillItemMapper jxcStockInbillItemMapper;
    @Resource
    private JxcSaleReturnBillMapper jxcSaleReturnBillMapper;
    @Resource
    private JxcSaleReturnBillDetailMapper jxcSaleReturnBillDetailMapper;
    @Resource
    private JxcBuyOrderMapper jxcBuyOrderMapper;
    @Resource
    private JxcBuyOrderDetailMapper jxcBuyOrderDetailMapper;
    @Resource
    private BaseCodeRuleService baseCodeRuleService;
    @Resource
    private JxcStockInbillItemService jxcStockInbillItemService;
    @Resource
    private JxcStockJob jxcStockJob;
    @Resource
    private JxcStockGoodsMapper jxcStockGoodsMapper;

    @Override
    public JxcStockInbill getJxcStockInbillById(Long id) throws Exception {
        return jxcStockInbillMapper.selectByPrimaryKey(id);
    }

    @Override
    public JxcStockInbillExt queryBySid(String sid) throws Exception {
        JxcStockInbillExt inbillExt = jxcStockInbillMapper.selectBySid(sid);
        if (inbillExt != null) {
            List<JxcStockInbillItemExt> itemExtList = jxcStockInbillItemService.queryValidByBillList(Collections.singletonList(sid));
            inbillExt.setItem_list(itemExtList);
        }
        return inbillExt;
    }

    @Override
    public void deleteJxcStockInbills(List<String> list, SysUser opUser) throws Exception {
        if (HlpUtils.isEmptyList(list)) {
            return;
        }
        BatchDeleteLogicVo logicVo = new BatchDeleteLogicVo(opUser);
        logicVo.setSidList(list);
        jxcStockInbillMapper.deleteLogicBySidList(logicVo);
        // 删除明细
        jxcStockInbillItemMapper.deleteLogicByBillList(logicVo);

        // 还原单据“生成入库单”
        jxcSaleReturnBillDetailMapper.restoreInBill(list);
        jxcSaleReturnBillMapper.restoreInBill(list);
        List<String> srcList = jxcStockInbillItemMapper.selectSrcSidBBillSids(list);
        List<String> sidList = jxcBuyOrderMapper.selectSidByDetailSidList(srcList);
        if (!HlpUtils.isEmptyList(srcList)) {
            jxcBuyOrderDetailMapper.updateInQty(srcList);
        }
        if (!HlpUtils.isEmptyList(sidList)) {
            jxcBuyOrderMapper.updateInBill(sidList);
        }
    }

    @Override
    public boolean isDuplicated(Object obj, String code) {
        if (obj == null) {
            return false;
        }
        JxcStockInbillExt inbillExt = (JxcStockInbillExt) obj;
        inbillExt.setCode(code);
        return jxcStockInbillMapper.selectDuplicatedCode(inbillExt) != null;
    }

    @Override
    public void saveJxcStockInbill(JxcStockInbillExt record, SysUser opUser) throws Exception {
        if (HlpUtils.isEmpty(record.getId())) {
            if (!HlpUtils.isEmpty(record.getCode())) {
                //如果是手动设置了编号，则检查是否有相同的，有的话，置空后重新生成
                JxcStockInbillExt same = jxcStockInbillMapper.selectDuplicatedCode(record);
                if (same != null) {
                    record.setCode(null);
                }
            }
            String genCode = baseCodeRuleService.genCode(null, JxcCodeRuleConstants.TYPE_JXC_IN_BILL, JxcCodeRuleConstants.TYPE_NAME_JXC_IN_BILL, opUser, record.getCode(), record, this);
            record.setCode(genCode);
            if (HlpUtils.isEmpty(record.getAudit_state())) {
                record.setAudit_state(Constants.VALUE_NO);
            }
            if (HlpUtils.isEmpty(record.getExecute_state())) {
                record.setExecute_state(Constants.VALUE_NO);
            }
            super.autoInjectBaseData(record, opUser, this.TYPE_CREATE, new Date(), record.getIn_date());
            jxcStockInbillMapper.insertSelective(record);
        } else {
            JxcStockInbillExt same = jxcStockInbillMapper.selectDuplicatedCode(record);
            if (same != null) {
                throw new HlpException("已存在相同编号的记录");
            }
            super.autoInjectBaseData(record, opUser, this.TYPE_UPDATE);
            super.updateYyyyMmdd(record, record.getIn_date());
            jxcStockInbillMapper.updateByPrimaryKeySelective(record);
        }
        jxcStockInbillItemService.saveJxcStockInbillItem(record, opUser);
    }

    @Override
    public List<JxcStockInbillExt> findJxcStockInbills(Map<String, Object> params, PageBean page) throws Exception {
        if (params.containsKey("goods_name")) {
            String goods_name = HlpUtils.getString(params, "goods_name");
            if (!HlpUtils.isEmpty(goods_name)) {
                List<JxcStockInbillItemExt> list = jxcStockInbillItemMapper.selectByGoodsName(goods_name);
                if (list == null || list.isEmpty()) {
                    return null;
                }
                List<String> inBillSids = ListUtil.map(list, JxcStockInbillItemExt::getInbill_sid).stream().distinct().collect(Collectors.toList());
                params.put("inBillSids", inBillSids);
            }
        }
        return jxcStockInbillMapper.selectByPage(params, page);
    }

    @Override
    public List<JxcStockInbillExt> findJxcStockInbills(Map<String, Object> params) throws Exception {
        return jxcStockInbillMapper.selectByParams(params);
    }

    @Override
    public HttpResult<Object> changeJxcStockInbillAuditState(List<String> sidList, Integer state, SysUserExt opUser) throws Exception {
        JxcStockInbillExt params = new JxcStockInbillExt();
        params.setDr(0);
        params.setSid_list(sidList);
        List<JxcStockInbillExt> billExtList = jxcStockInbillMapper.selectByEntity(params);
        if (HlpUtils.isEmptyList(billExtList)) {
            return null;
        }
        // 检查是否已生成对账单
        if (JxcUtils.isGenReconciliationByStockBill()) {
            List<JxcStockInbillExt> filter = ListUtil.filter(billExtList, t -> !HlpUtils.isEmpty(t.getPay_req_state()) && Constants.VALUE_NO != t.getPay_req_state());
            if (!HlpUtils.isEmptyList(filter)) {
                List<String> codeList = ListUtil.map(filter, JxcStockInbillExt::getCode);
                String msg = "入库单：" + StringUtils.join(codeList, "、") + " 已生成对账单，无法" + (Constants.VALUE_YES == state ? "审核" : "反审");
                return HttpResult.fail(ErrorCode.CODE_PROC_ERROR,msg);
            }
        }
        // 审核时检查是否选择了仓位：1、获取单据；2、获取单据明细；3、检查单据明细是否选择仓位；4、检查单据明细仓位的数量与单据明细数量是否一致
        StringBuilder builder = new StringBuilder();
        List<String> inBillSids = ListUtil.map(billExtList, JxcStockInbillExt::getSid);
        List<JxcStockInbillItemExt> itemExtList = jxcStockInbillItemMapper.selectBySids(inBillSids, 0);
        if (itemExtList == null || itemExtList.isEmpty()) {
            return null;
        }
        List<String> inBillItemSids = ListUtil.map(itemExtList, JxcStockInbillItemExt::getSid);
        // 遍历单据
        for (JxcStockInbillExt inbillExt : billExtList) {
            // 获取单据明细
            List<JxcStockInbillItemExt> filterItemList = ListUtil.filter(itemExtList, t -> inbillExt.getSid().equals(t.getInbill_sid()));
            // 遍历单据明细
            for (JxcStockInbillItemExt inbillItemExt : filterItemList) {
            }
        }
        if (builder.length() > 0) {
            throw new HlpException(builder.toString());
        }
        StringBuilder buf = new StringBuilder();
        for (JxcStockInbillExt billExt : billExtList) {
            if (state == 1) {
                if (HlpUtils.isEmpty(billExt.getWarehouse_sid())){
                    if (buf.length()>0){
                        buf.append(",");
                    }
                    buf.append(billExt.getCode());
                    continue;
                }
                billExt.setAudit_state(Constants.VALUE_YES);
                billExt.setAuditor_sid(opUser.getSid());
                billExt.setAuditor_name(opUser.getName());
                billExt.setAudit_date(new Date());
            } else if (state == -1) {
                billExt.setAudit_state(Constants.VALUE_NO);
                billExt.setAuditor_sid(null);
                billExt.setAuditor_name(null);
                billExt.setAudit_date(null);
            }
            super.autoInjectBaseData(billExt, opUser, this.TYPE_UPDATE);
        }
        if (buf.length()>0) {
            String msg = "入库单的仓库为空：" + buf.toString();
            return HttpResult.fail(ErrorCode.CODE_PROC_ERROR, msg);
        }
        ThreadPoolTaskUtil.executeInList4Split(billExtList, false, list -> {
            jxcStockInbillMapper.updateList(list);
        });

        // 加入队列：更新 jxc_stock_goods_position 等待入库数量
        String code = state == 1 ? StockConstants.OPERATE_ADD : StockConstants.OPERATE_SUB;
        for (JxcStockInbillExt billExt : billExtList) {
            jxcStockJob.addJxcStockQue(code, StockConstants.BIZ_NAME_IN_BILL, "updateStockQtyIning2StockGoodsPosition", billExt.getId(), opUser);
        }
        return null;
    }


    @Override
    public void executeJxcStockInbill(List<String> sidList, SysUserExt opUser) throws Exception {
        JxcStockInbillExt params = new JxcStockInbillExt();
        params.setDr(0);
        params.setSid_list(sidList);
        List<JxcStockInbillExt> billExtList = jxcStockInbillMapper.selectByEntity(params);
        if (HlpUtils.isEmptyList(billExtList)) {
            return;
        }

        List<JxcStockInbillExt> filterNoAuditList = ListUtil.filter(billExtList, t -> t.getAudit_state() == Constants.VALUE_NO);
        if (!HlpUtils.isEmptyList(filterNoAuditList)) {
            List<String> codeList = ListUtil.map(filterNoAuditList, JxcStockInbillExt::getCode);
            throw new HlpException(String.format("入库单：%s 未审核，无法执行入库操作", StringUtils.join(codeList, "、")));
        }
        List<JxcStockInbillExt> filterExecutedList = ListUtil.filter(billExtList, t -> t.getExecute_state() == Constants.VALUE_YES);
        if (!HlpUtils.isEmptyList(filterExecutedList)) {
            List<String> codeList = ListUtil.map(filterExecutedList, JxcStockInbillExt::getCode);
            throw new HlpException(String.format("入库单：%s 已入库", StringUtils.join(codeList, "、")));
        }

        Date now = new Date();
        for (JxcStockInbillExt billExt : billExtList) {
            super.autoInjectBaseData(billExt, opUser, this.TYPE_UPDATE);
            billExt.setExecute_state(Constants.VALUE_YES);
            billExt.setExecute_date(now);
            billExt.setExecutor_sid(opUser.getSid());
            billExt.setExecutor_name(opUser.getName());
            billExt.setExecute_yyyy(DateUtil.getYyyy(now));
            billExt.setExecute_yyyymm(DateUtil.getYyyyMM(now));
            billExt.setExecute_yyyymmdd(DateUtil.getYyyyMMdd(now));
        }
        ThreadPoolTaskUtil.executeInList4Split(billExtList, false, list -> {
            jxcStockInbillMapper.updateList(list);
        });

        //更新 jxc_stock_goods库存数量
        Map<String,Object> par = new HashMap<>(2);
        par.put("op",1);
        for (JxcStockInbillExt billExt : billExtList) {
            par.put("inbill_sid",billExt.getSid());
            jxcStockGoodsMapper.updateQtyFromInBill(par);
        }
    }

    @Override
    public List<JxcStockInbillExt> findJxcStockInbillsIncludeDetail(Map<String, Object> params, PageBean page) {
        return jxcStockInbillMapper.selectStockInbillsIncludeDetailByPage(params, page);
    }

    @Override
    public List<JxcStockInbillExt> queryJxcStockInBillData4Print(List<String> sidList) throws Exception {
        List<JxcStockInbillExt> list = ThreadPoolTaskUtil.queryInList4Split(sidList, itemList -> {
            JxcStockInbillExt params = new JxcStockInbillExt();
            params.setDr(0);
            params.setSid_list(itemList);
            return jxcStockInbillMapper.selectByEntity(params);
        });
        if (!HlpUtils.isEmptyList(list)) {
            List<String> billList = ListUtil.map(list, JxcStockInbillExt::getSid);
            List<JxcStockInbillItemExt> itemExtList = jxcStockInbillItemService.queryValidByBillList(billList);
            for (JxcStockInbillExt billExt : list) {
                List<JxcStockInbillItemExt> filterList = ListUtil.filter(itemExtList, t -> t.getInbill_sid().equals(billExt.getSid()));
                billExt.setItem_list(filterList);
            }
        }
        return list;
    }

    @Override
    public List<JxcStockInbillExt> queryBySrcSid(List<String> list, int dr) {
        return jxcStockInbillMapper.selectBySrcSid(list, dr);
    }

    @Override
    public void cancelExecuteJxcStockInbill(List<String> sidList, SysUserExt opUser) throws Exception {
        JxcStockInbillExt params = new JxcStockInbillExt();
        params.setDr(0);
        params.setSid_list(sidList);
        List<JxcStockInbillExt> billExtList = jxcStockInbillMapper.selectByEntity(params);
        if (HlpUtils.isEmptyList(billExtList)) {
            return;
        }

        List<JxcStockInbillExt> filterExecutedList = ListUtil.filter(billExtList, t -> t.getExecute_state() == Constants.VALUE_NO);
        if (!HlpUtils.isEmptyList(filterExecutedList)) {
            List<String> codeList = ListUtil.map(filterExecutedList, JxcStockInbillExt::getCode);
            throw new HlpException(String.format("入库单：%s 未入库", StringUtils.join(codeList, "、")));
        }

        for (JxcStockInbillExt billExt : billExtList) {
            super.autoInjectBaseData(billExt, opUser, this.TYPE_UPDATE);
            billExt.setExecute_state(Constants.VALUE_NO);
            billExt.setExecute_date(null);
            billExt.setExecutor_sid(null);
            billExt.setExecutor_name(null);
            billExt.setExecute_yyyy(null);
            billExt.setExecute_yyyymm(null);
            billExt.setExecute_yyyymmdd(null);
            jxcStockInbillMapper.updateByPrimaryKey(billExt);
        }
        //更新 jxc_stock_goods库存数量
        Map<String,Object> par = new HashMap<>(2);
        par.put("op",-1);
        for (JxcStockInbillExt billExt : billExtList) {
            par.put("inbill_sid",billExt.getSid());
            jxcStockGoodsMapper.updateQtyFromInBill(par);
        }
    }
}
